#include "syscall.h"

#define NUM_MAX_CARS 				150
#define NUM_MAX_TMASTERS		10
#define NUM_MAX_VALETS 			150
#define NUM_MAX_VISITORS		600

int nNumTotalCars = 6;
int nNumTotalValets = 2;
int nNumTotalTicketMasters = 1;

static int nDriverArrived = 0;
static int nVisitorsArrived = 0;
static int nValetsArrived = 0;
static int nTicketMasterArrived = 0;

int nValetsInBackRoom = 0;

int nCarsWaitingtoPark = 0;
int lockCarsWaitingtoPark;

int nVisitorsInCar[NUM_MAX_VISITORS];
int nTotalVisitorsInCar[NUM_MAX_VISITORS];
int nVisitorTOCar[NUM_MAX_VISITORS];

int nDriver[NUM_MAX_CARS];
int driverHasToken[NUM_MAX_CARS];
int isLimo[NUM_MAX_CARS];
int nLimoWaitingCounter = 0;
int driverReady[NUM_MAX_CARS];
static int nCarsReady = 0;

int lockIsTicketMasterAvailable[NUM_MAX_TMASTERS];
int isTicketMasterAvailable[NUM_MAX_TMASTERS];
int ticketMasterVisitorNum[NUM_MAX_TMASTERS];

int lockIsValetAvailable[NUM_MAX_VALETS];
int isValetAvailable[NUM_MAX_VALETS];
int valetParkOrRetrieve[NUM_MAX_VALETS]; 		/*	-1 = not initialized, 1 = Park, 2 = Retrieve */
int nValetParkingCarNum[NUM_MAX_VALETS];

int threadDriver[NUM_MAX_CARS];
int threadVisitor[NUM_MAX_VISITORS];
int threadValets[NUM_MAX_VALETS];
int threadTicketMasters[NUM_MAX_TMASTERS];
int threadValetManager;

int lockThreadID;
int lockCars[NUM_MAX_CARS];
int lockDriverMaster;
int lockLimoWaitingCounter;

int lockValetManager;
int cvValetManager;

int lockVisitorMaster;
int lockVisitorInCar[NUM_MAX_CARS];

int lockValetManagerMaster;
int lockTicketMasterMaster;
int lockValetMaster;

int cvDriverWaiting[NUM_MAX_CARS];
int cvValetWaiting[NUM_MAX_VALETS];
int cvTicketMasterWaiting[NUM_MAX_TMASTERS];

void InitializeSimulation()
{
	int i = 0;
	int s = 0;
	
	/***************************************************************
	********************Input Section*******************************
	****************************************************************/
	Write("--> Enter total Number of Cars (MAX = 150) : \n", 47, 1);
	nNumTotalCars = GetInputInt("Number Of Cars", 15);
	if (nNumTotalCars <= 0 || nNumTotalCars >= (NUM_MAX_CARS-1))
	{
		Write("--> Invalid value entered - Setting to default of 6\n", 53, 1);
		nNumTotalCars = 6;
	}
	
	Write("--> Enter total Number of Valets (MAX = 150) : \n", 49, 1);
	nNumTotalValets = GetInputInt("Number Of Valets", 18);
	if ( nNumTotalValets <= 0 || nNumTotalValets >= (NUM_MAX_VALETS -1))
	{
		Write("--> Invalid value entered - Setting to default of 2\n", 53, 1);
		nNumTotalValets = 2; 
	}	
	
	Write("--> Enter total Number of Ticket Masters (MAX = 10) : \n", 57, 1);
	nNumTotalTicketMasters = GetInputInt("Number Of Ticket Masters", 26);
	if ( nNumTotalTicketMasters <= 0 || nNumTotalTicketMasters >= (NUM_MAX_TMASTERS -1))
	{
		Write("--> Invalid value entered - Setting to default of 1\n", 53, 1);
		nNumTotalTicketMasters = 1; 
	}
	
	/***************************************************************
	********************Initialize Car details**********************
	****************************************************************/
	for (i = 0; i < nNumTotalCars; i++)
	{
		nDriver[i] = -1;
		driverReady[i] = 0;
		nVisitorsInCar[i] = 3;
		if ( i % 2 == 0)
			isLimo[i] = 1; 			/* 1 = Limo */
		else
			isLimo[i] = 0;			/* 3 = Limo */
			
		nTotalVisitorsInCar[i] = 0;
		
		if(isLimo[i])
		{
			WriteOutputInt("--> Limo arrived : #", 24,i);
			lockCars[i] = CreateLock("LimoLock", 10, 0);
			cvDriverWaiting[i] = CreateCondition("LimoCondition", 15, 0);
		}	
		else
		{
			WriteOutputInt("--> Car arrived : #", 23,i);
			lockCars[i] = CreateLock("CarLock", 8, 0);
			cvDriverWaiting[i] = CreateCondition("DriverCondition", 18, 0);
		}
		
		driverHasToken[i] = 0;
		lockVisitorInCar[i]				= CreateLock("Visitors In Car", 16, 0);
	}
	
	/***************************************************************
	********************Initialize Valets***************************
	****************************************************************/
	
	for (i = 0; i < NUM_MAX_VALETS; i++)
	{
		lockIsValetAvailable[i] = CreateLock("Valet Available Lock", 22, 0);
		isValetAvailable[i] 		= -1;
		cvValetWaiting[i] 			= CreateCondition("ValetCondition", 19, 0);
		valetParkOrRetrieve[i] 	= -1;
		nValetParkingCarNum[i]  = -1;
	}
	
	/***************************************************************
	********************Initialize Ticket Masters*******************
	****************************************************************/
	for (i = 0; i < NUM_MAX_TMASTERS; i++)
	{
		lockIsTicketMasterAvailable[i] 	= CreateLock("Ticket Master Lock", 19, 0);
		isTicketMasterAvailable[i] 			= -1;
		cvTicketMasterWaiting[i] 				= CreateCondition("TicketMasterCondition", 22,0);
		ticketMasterVisitorNum[i]				= -1;
	}
	
	/***************************************************************
	********************Create Control Locks************************
	****************************************************************/
	
	lockDriverMaster 				= CreateLock("Driver Register Lock", 22, 0);
	lockLimoWaitingCounter 	= CreateLock("Limo Waiting Lock", 19, 0); 
	lockThreadID						= CreateLock("Thread ID Lock", 15, 0);
	lockVisitorMaster				= CreateLock("Visitor Register Lock", 24, 0);
	lockValetMaster					=	CreateLock("Valet Register Lock", 22, 0);
	lockCarsWaitingtoPark		= CreateLock("Car Waiting to Park Lock", 28,0);
	lockTicketMasterMaster	= CreateLock("Ticket Master Register Lock", 32, 0);
	lockValetManagerMaster	=	CreateLock("Valet Manager Register Lock", 32, 0);

	lockValetManager				=	CreateLock("Valet Manager Lock", 20, 0);
	cvValetManager					= CreateCondition("ValetManagerCondition", 23, 0);
		
	s = GetInputInt("Any # to continue", 20);
}

/**********************************************************************
********************DriverThreadHandler********************************
***********************************************************************/
int handover_keys(int nDriverIndex, int valetFound)
{
	AcquireLock(lockIsValetAvailable[valetFound], 0);
		nValetParkingCarNum[valetFound] = nDriverIndex;
		SignalConditionVariable(lockIsValetAvailable[valetFound], cvValetWaiting[valetFound]);
	ReleaseLock(lockIsValetAvailable[valetFound], 0);
	
	WriteOutput2Int("Keys Given::Driver ->> Valet",29, nDriverIndex, valetFound); 			
	return 0;
}

int handover_tip(int nDriverIndex, int valetFound)
{
	AcquireLock(lockIsValetAvailable[valetFound], 0);
		nValetParkingCarNum[valetFound] = nDriverIndex;
		SignalConditionVariable(lockIsValetAvailable[valetFound], cvValetWaiting[valetFound]);
	ReleaseLock(lockIsValetAvailable[valetFound], 0);
	
	WriteOutput2Int("Tip Given::Driver ->> Valet",28, nDriverIndex, valetFound); 			
	return 0;
}

int find_a_valet(int nDriverIndex, int nParkOrRetrieve)
{
	int i = 0;
	
	for (i = 0; i < nNumTotalValets; i++)
	{
		AcquireLock(lockIsValetAvailable[i],0);
			if (isValetAvailable[i] == 1)
			{
				WriteOutputInt("Available Valet", 16, i);
				isValetAvailable[i] = -1;
				valetParkOrRetrieve[i] = nParkOrRetrieve;
				ReleaseLock(lockIsValetAvailable[i],0);
				return i;
			}
			else
				ReleaseLock(lockIsValetAvailable[i],0);
	}
	
	WriteOutputInt("No Valet Available for Car", 28, nDriverIndex);
	return -1;
}

void wait_for_all_visitors_to_disembark(int nDriverIndex)
{
	WriteOutputInt("--> Waiting for car to get empty, Driver #", 43, nDriverIndex);
	
	AcquireLock(lockCars[nDriverIndex],1);
	
	AcquireLock(lockVisitorInCar[nDriverIndex], 1);
	driverReady[nDriverIndex] = 1;
	nCarsReady++;
	if (nVisitorsInCar[nDriverIndex] != 0 && nTotalVisitorsInCar[nDriverIndex] == 3)
		WaitConditionVariable(lockVisitorInCar[nDriverIndex], cvDriverWaiting[nDriverIndex]);
	
	ReleaseLock(lockVisitorInCar[nDriverIndex], 1);
	ReleaseLock(lockCars[nDriverIndex], 1);
	
	WriteOutputInt("Empty Car # ", 13, nDriverIndex);
}

void wait_for_all_visitors_to_embark(int nDriverIndex)
{
	WriteOutputInt("--> Waiting for car to get Full, Driver #", 43, nDriverIndex);
	
	AcquireLock(lockCars[nDriverIndex],1);
	
	AcquireLock(lockVisitorInCar[nDriverIndex], 1);
	driverReady[nDriverIndex] = 1;
	nCarsReady++;
	if (nVisitorsInCar[nDriverIndex] == nTotalVisitorsInCar[nDriverIndex])
		WaitConditionVariable(lockVisitorInCar[nDriverIndex], cvDriverWaiting[nDriverIndex]);
	
	ReleaseLock(lockVisitorInCar[nDriverIndex], 1);
	ReleaseLock(lockCars[nDriverIndex], 1);
	
	WriteOutputInt("Full Car # ", 13, nDriverIndex);
}

int driver_find_a_ticket_master(int nVisitorIndex)
{
	int i = 0;
	
	for (i = 0; i < nNumTotalTicketMasters; i++)
	{
		AcquireLock(lockIsTicketMasterAvailable[i],0);
			if (isTicketMasterAvailable[i] == 1)
			{
				WriteOutput2Int("Available Ticket Master ->> Driver", 39, i, nVisitorIndex);
				isTicketMasterAvailable[i] = -1;
				SignalConditionVariable(lockIsTicketMasterAvailable[nVisitorIndex], cvTicketMasterWaiting[nVisitorIndex]);
				ReleaseLock(lockIsTicketMasterAvailable[i],0);
				return i;
			}
			else
				ReleaseLock(lockIsTicketMasterAvailable[i],0);
	}
	
	WriteOutputInt("Waiting in Queue, Driver", 26, nVisitorIndex);
	return -1;
}

int driver_validate_ticket(int nVisitorIndex, int ticketMasterFound)
{
	AcquireLock(lockIsTicketMasterAvailable[ticketMasterFound], 0);
		ticketMasterVisitorNum[ticketMasterFound] = nVisitorIndex;
		SignalConditionVariable(lockIsTicketMasterAvailable[ticketMasterFound], cvTicketMasterWaiting[ticketMasterFound]);
	ReleaseLock(lockIsTicketMasterAvailable[ticketMasterFound], 0);
	
	WriteOutput2Int("Ticket validated::Driver ->> Ticket Master", 44, nVisitorIndex, ticketMasterFound); 			
	return 0;
}

/**********************************************************************
********************DriverThreadHandler********************************
***********************************************************************/

void DriverThreadHandler()
{
	int nThreadID = 0;
	int nDriverIndex = 0;
	int i = 0;
	int valetFound = -1;
	int ticketMasterFound = -1;
	
	AcquireLock(lockDriverMaster, 0);
		nThreadID = GetCurThreadID(0);
		nDriver[nDriverArrived] = nThreadID;
		nDriverIndex = nDriverArrived;
		nDriverArrived++;
	ReleaseLock(lockDriverMaster, 0);
	
	WriteOutputInt("***STARTING Driver = \t", 24, nDriverIndex);
	
	if(isLimo[nDriverIndex] == 1)
	{
		AcquireLock(lockLimoWaitingCounter, 0);
		nLimoWaitingCounter = nLimoWaitingCounter + 1;
		ReleaseLock(lockLimoWaitingCounter, 0);
	}
	else
	{
		while(1)
		{
			AcquireLock(lockLimoWaitingCounter, 0);
			if (nLimoWaitingCounter > 0)
			{
				ReleaseLock(lockLimoWaitingCounter, 0);
				WriteOutputInt("--> Limo in queue, Waiting Car #\t", 33, nDriverIndex);
				
				WriteOutputInt("--> Limos in QUEUE = ", 23,nLimoWaitingCounter);

				YieldThread(0);
			}	
			else 
				break;
		}
		ReleaseLock(lockLimoWaitingCounter, 0);
	}
	
	if(isLimo[nDriverIndex] == 1)
	{
		AcquireLock(lockLimoWaitingCounter, 1);
			nLimoWaitingCounter = nLimoWaitingCounter - 1;
		ReleaseLock(lockLimoWaitingCounter, 1);
		WriteOutputInt("--> Limo in Drive Way", 21, nDriverIndex);
	}
	else
	{
		WriteOutputInt("--> Car in Drive Way", 20, nDriverIndex);
	}
	
	wait_for_all_visitors_to_disembark(nDriverIndex);
	
	AcquireLock(lockCarsWaitingtoPark, 0);
	nCarsWaitingtoPark++;
	ReleaseLock(lockCarsWaitingtoPark, 0);
	
	do
	{
		valetFound = find_a_valet(nDriverIndex, 1);
		if (valetFound < 0)
			Yield(0);
	}while(valetFound < 0);
	
	handover_keys(nDriverIndex, valetFound);
	WriteOutputInt("Going to Museum, Driver",22, nDriverIndex);
	valetFound = -1;
		
	WriteOutputInt("In Museum, Driver",18, nDriverIndex);
		
	for (i = 0; i < 200; i++)
	{
		Yield(0);
	}

	AcquireLock(lockCarsWaitingtoPark, 0);
	nCarsWaitingtoPark++;
	ReleaseLock(lockCarsWaitingtoPark, 0);
	
	wait_for_all_visitors_to_embark(nDriverIndex);
	
	do
	{
		valetFound = find_a_valet(nDriverIndex, 2);
		if (valetFound < 0)
			Yield(0);
	}while(valetFound < 0);
	handover_tip(nDriverIndex, valetFound);
	
	Exit(1);
}
/**********************************************************************
********************DriverThreadHandler********************************
***********************************************************************/

/**********************************************************************
********************VisitorThreadHandler*******************************
***********************************************************************/
void disembark_visitors(int nCarIndex, int nVisitorsIndex)
{
	WriteOutputInt("Disembarking Visitor from Car #", 32, nCarIndex);
	AcquireLock(lockVisitorInCar[nCarIndex], 1);
	nVisitorsInCar[nCarIndex]--;
	if(nVisitorsInCar[nCarIndex] == 0)
		SignalConditionVariable(lockVisitorInCar[nCarIndex], cvDriverWaiting[nCarIndex]);
	
	ReleaseLock(lockVisitorInCar[nCarIndex]);
	
	WriteOutput2Int("Visitor Disembarked ->> Car", 28, nCarIndex, nVisitorsIndex);
}

void embark_visitors(int nCarIndex, int nVisitorsIndex)
{
	WriteOutput2Int("Embarking Visitor - Car", 24, nVisitorsIndex, nCarIndex);
	
	AcquireLock(lockVisitorInCar[nCarIndex], 1);
	nVisitorsInCar[nCarIndex]++;
	if(nVisitorsInCar[nCarIndex] >= nTotalVisitorsInCar[nCarIndex] || nVisitorsInCar[nCarIndex] == 3)
		SignalConditionVariable(lockVisitorInCar[nCarIndex], cvDriverWaiting[nCarIndex]);
	
	ReleaseLock(lockVisitorInCar[nCarIndex]);
	
	WriteOutput2Int("Visitor Embarked ->> Car", 25, nCarIndex, nVisitorsIndex);
}

int find_a_ticket_master(int nVisitorIndex)
{
	int i = 0;
	
	for (i = 0; i < nNumTotalTicketMasters; i++)
	{
		AcquireLock(lockIsTicketMasterAvailable[i],0);
			if (isTicketMasterAvailable[i] == 1)
			{
				WriteOutput2Int("Available Ticket Master ->> Visitor", 39, i, nVisitorIndex);
				isTicketMasterAvailable[i] = -1;
				SignalConditionVariable(lockIsTicketMasterAvailable[nVisitorIndex], cvTicketMasterWaiting[nVisitorIndex]);
				ReleaseLock(lockIsTicketMasterAvailable[i],0);
				return i;
			}
			else
				ReleaseLock(lockIsTicketMasterAvailable[i],0);
	}
	
	WriteOutputInt("Waiting in Queue, Visitor", 26, nVisitorIndex);
	return -1;
}

int validate_ticket(int nVisitorIndex, int ticketMasterFound)
{
	AcquireLock(lockIsTicketMasterAvailable[ticketMasterFound], 0);
		ticketMasterVisitorNum[ticketMasterFound] = nVisitorIndex;
		SignalConditionVariable(lockIsTicketMasterAvailable[ticketMasterFound], cvTicketMasterWaiting[ticketMasterFound]);
	ReleaseLock(lockIsTicketMasterAvailable[ticketMasterFound], 0);
	
	WriteOutput2Int("Ticket validated::Visitor ->> Ticket Master", 44, nVisitorIndex, ticketMasterFound); 			
	return 0;
}

/**********************************************************************
********************VisitorThreadHandler*******************************
***********************************************************************/

void VisitorThreadHandler()
{
	int nThreadID = 0;
	int nVisitorIndex = 0;
	int i = 0;
	int ticketMasterFound = -1;
	
	AcquireLock(lockVisitorMaster, 0);
		nThreadID = GetCurThreadID(0);
		nVisitorIndex = nVisitorsArrived;
		nVisitorTOCar[nVisitorIndex] = nVisitorsArrived / 3;
		nTotalVisitorsInCar[nVisitorTOCar[nVisitorIndex]]++;		
		nVisitorsArrived++;
	ReleaseLock(lockVisitorMaster, 0);
	
	WriteOutputInt("***STARTING Visitor = \t", 24, nVisitorIndex);
	
	disembark_visitors(nVisitorTOCar[nVisitorIndex], nVisitorIndex);
	
	do
	{
		ticketMasterFound = find_a_ticket_master(nVisitorIndex);
		if (ticketMasterFound < 0)
			Yield(0);
	}while(ticketMasterFound < 0);

	validate_ticket(nVisitorIndex, ticketMasterFound);
	
	for (i = 0; i < 200; i++)
	{
		Yield(0);
	}
	
	embark_visitors(nVisitorTOCar[nVisitorIndex], nVisitorIndex);
	
	Exit(1);
}
/**********************************************************************
********************VisitorThreadHandler*******************************
***********************************************************************/

/**********************************************************************
**********************ValetThreadHandler*******************************
***********************************************************************/
int available_valets()
{
	int Count = 0;
	int i = 0;
	
	for (i = 0; i < nNumTotalValets; i++)
	{
		AcquireLock(lockIsValetAvailable[i],0);
		if (isValetAvailable[i] == 1)
		{
			Count++;
			ReleaseLock(lockIsValetAvailable[i],0);
		}
		else
			ReleaseLock(lockIsValetAvailable[i],0);
	}
		
	return Count;
}

void valet_park_car(int nValetIndex)
{
	int i = 0;
	
	WriteOutputInt("Waiting for Car to Park, Valet", 32, nValetIndex);
	AcquireLock(lockIsValetAvailable[nValetIndex], 0);
		isValetAvailable[nValetIndex] = 1;
		WaitConditionVariable(lockIsValetAvailable[nValetIndex], cvValetWaiting[nValetIndex]);
		
		if (valetParkOrRetrieve[nValetIndex] == 1)
		{
			WriteOutput2Int("Valet Parking Car::Valet ->> Car", 35, nValetIndex, nValetParkingCarNum[nValetIndex]);
			AcquireLock(lockCarsWaitingtoPark, 0);
				nCarsWaitingtoPark--;
			ReleaseLock(lockCarsWaitingtoPark, 0);
		}	
		else if (valetParkOrRetrieve[nValetIndex] == 1)
		{
			WriteOutput2Int("Valet Retrieving Car::Valet ->> Car", 40, nValetIndex, nValetParkingCarNum[nValetIndex]);
			AcquireLock(lockCarsWaitingtoPark, 0);
				nCarsWaitingtoPark--;
			ReleaseLock(lockCarsWaitingtoPark, 0);
		}
		SignalConditionVariable(lockValetManager, cvValetManager);
	ReleaseLock(lockIsValetAvailable[nValetIndex], 0);
	
	for (i = 0; i < 25; i++)
		Yield(0);
	
	WriteOutput2Int("Valet # ->> Cars Waiting", 27, nValetIndex, nCarsWaitingtoPark);
}

void ValetThreadHandler()
{
	int nThreadID = 0;
	int nValetIndex = 0;
	
	int i = 0;
	
	AcquireLock(lockValetMaster, 0);
		nThreadID = GetCurThreadID(0);
		nValetIndex = nValetsArrived;
		nValetsArrived++;
	ReleaseLock(lockValetMaster, 0);
	
	WriteOutputInt("***STARTING Valet = \t", 22, nValetIndex);
	
	while(1)
	{
		valet_park_car(nValetIndex);
	}
	
	Exit(1);
}
/**********************************************************************
**********************ValetThreadHandler*******************************
***********************************************************************/


/**********************************************************************
**********************TicketMasterThreadHandler************************
***********************************************************************/
void validate_visitor_tickets(int nTicketMasterIndex)
{
	WriteOutputInt("Waiting for a Visitor, Ticket Master", 38, nTicketMasterIndex);
	
	AcquireLock(lockIsTicketMasterAvailable[nTicketMasterIndex], 0);
		isTicketMasterAvailable[nTicketMasterIndex] = 1;
		WaitConditionVariable(lockIsTicketMasterAvailable[nTicketMasterIndex], cvTicketMasterWaiting[nTicketMasterIndex]);
	ReleaseLock(lockIsTicketMasterAvailable[nTicketMasterIndex], 0);
	
	WriteOutput2Int("Validating::Ticket Master - Visitor", 36, nTicketMasterIndex, ticketMasterVisitorNum[nTicketMasterIndex]);
}

void TicketMasterThreadHandler()
{
	int nThreadID = 0;
	int nTicketMasterIndex = 0;
	
	int i = 0;
	
	AcquireLock(lockTicketMasterMaster, 0);
		nThreadID = GetCurThreadID(0);
		nTicketMasterIndex = nTicketMasterArrived;
		nTicketMasterArrived++;
	ReleaseLock(lockTicketMasterMaster, 0);
	
	WriteOutputInt("***STARTING Ticket Master = \t", 30, nTicketMasterIndex);
	
	while(1)
	{
		validate_visitor_tickets(nTicketMasterIndex);
	}
	
	Exit(1);
}
/**********************************************************************
**********************TicketMasterThreadHandler************************
***********************************************************************/

/**********************************************************************
**********************ValetManagerThreadHandler************************
***********************************************************************/
void send_valet_to_backroom()
{
	int i = 0;
	
	for(i = (nNumTotalValets - 1); i = 0 ; i--)
	{
		AcquireLock(lockIsValetAvailable[i],0);
		if (isValetAvailable[i] == 1)
		{
			isValetAvailable[i] = -2;
			ReleaseLock(lockIsValetAvailable[i],0);
			WriteOutputInt("Valet Manager Backroom --> Valet", 35, i);
		}
		else
			ReleaseLock(lockIsValetAvailable[i],0);
	}
}

void perform_valet_manager_job()
{
	AcquireLock(lockValetManager);
		WaitConditionVariable(lockValetManager, cvValetManager);
	ReleaseLock(lockValetManager);
	
	if (nCarsWaitingtoPark < 4 && available_valets() > 4)
	{
		send_valet_to_backroom();
	}
}

void ValetManagerThreadHandler()
{
	int nThreadID = 0;
	
	AcquireLock(lockValetManagerMaster, 0);
		nThreadID = GetCurThreadID(0);
	ReleaseLock(lockValetManagerMaster, 0);
	
	while(1)
		perform_valet_manager_job();
		
	Exit(0);
}

/**********************************************************************
***************************** M A I N *********************************
***********************************************************************/
void main()
{
	int valetIndex = 0;
	int driverIndex = 0;
	int visitorIndex = 0;
	int ticketMasterIndex = 0;
	
	int lockMainMaster = 0;
	int visitorsNumber = 0;
	int tempIndex = 0;
	
	InitializeSimulation();
	visitorsNumber = nNumTotalCars * 3;
	
	lockMainMaster = CreateLock("Main Lock");

	/*=======================================================================
	  ==================Starting Ticket Master Threads=======================
	  =======================================================================*/
	for (ticketMasterIndex = 0; ticketMasterIndex < nNumTotalTicketMasters; ticketMasterIndex++)
	{
		threadTicketMasters[ticketMasterIndex] = Fork(TicketMasterThreadHandler, "TicketMasterThread", 19);
	}
	
	/*=======================================================================
	  ======================Starting Valet Threads===========================
	  =======================================================================*/
	for (valetIndex = 0; valetIndex < nNumTotalValets; valetIndex++)
	{
		threadValets[valetIndex] = Fork(ValetThreadHandler, "ValetThread", 12);
	}
	
	/*=======================================================================
	  ===================Starting Driver Threads=============================
	  =======================================================================*/
	  
	for (driverIndex = 0; driverIndex < nNumTotalCars; driverIndex++)
	{
		tempIndex = (driverIndex * 3 + visitorIndex);
			/*=======================================================================
	  	====================Starting Visitor Threads===========================
	  	=======================================================================*/
		for (visitorIndex = 0; visitorIndex < 3; visitorIndex++)
		{
				threadVisitor[tempIndex] = Fork(VisitorThreadHandler, "VisitorThread", 14);
		}

		if (isLimo[driverIndex] == 1)
			threadDriver[driverIndex] = Fork(DriverThreadHandler, "LimoThread", 13);
		else
			threadDriver[driverIndex] = Fork(DriverThreadHandler, "DriverThread", 15);
	}
	
	/*=======================================================================
	  ==================Starting Valet Manager Threads=======================
	  =======================================================================*/
		threadValetManager = Fork(ValetManagerThreadHandler, "ValetManagerThread", 19);
	
}